﻿#if UNITY_EDITOR
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Sirenix.OdinInspector;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Build;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEditor.Build.Pipeline.Utilities;
using UnityEngine;
using UnityEngine.AddressableAssets;
using File = UnityEngine.Windows.File;
using Object = UnityEngine.Object;

public enum ProjectType
{
    Development,
    Publish,
    DLC
}

/// <summary>
/// Addressable Group 资源管理工具
/// 通过路径管理资源，允许设置子路径，创建 group ，删除 group，设置 schema 状态
/// 一键构建状态，缓存 group 状态，设置 label（可以不填）
/// 在初始化的时候，update 内容
/// 切换 profile 状态
/// </summary>
[InlineEditor]
public class AddressablesGroupsManager : SerializedScriptableObject
{
    private const string defaultPath = "Assets/AddressableGroupsManagement.asset";
    private static AddressablesGroupsManager _manager;

    public static AddressablesGroupsManager Instance
    {
        get
        {
            Init();
            return _manager;
        }
    }

    [TableList] public List<GroupHandle> groups;

    [LabelText("工程类型"), OnValueChanged("ProjectTypeSwitch")] 
    public ProjectType PType = ProjectType.Development;

    [LabelText("是否清理现有 Group")] public bool isClearGroup = false;

    [LabelText("默认生成静态资源包")] public bool AllStatics = false;

    [MenuItem("Window/Asset Management/Custom/Save Group #H")]
    public static AddressablesGroupsManager Init()
    {
        _manager = AssetDatabase.LoadAssetAtPath<AddressablesGroupsManager>(defaultPath);
        if (_manager == null)
        {
            _manager = CreateInstance<AddressablesGroupsManager>();

            AssetDatabase.CreateAsset(_manager, defaultPath);

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        return _manager;
    }

    /// <summary>
    /// 构建 groups
    /// </summary>
    [Button("构建", ButtonSizes.Large), GUIColor(0.2f, 0.95f, 0.12f), FoldoutGroup("构建")]
    public void Build()
    {
        if (groups == null || groups.Count <= 0)
        {
            Debug.LogError("【AAGroupManager】 Groups 为空，执行完成");
            return;
        }

        ClearGroups();
        
        switch (PType)
        {
            case ProjectType.Development:
                defaultBuild();
                break;
            case ProjectType.Publish:
                publishBuild();
                break;
            case ProjectType.DLC:
                dlcBuild();
                break;
            default:
                break;
        }
        
        //
        // if (AllStatics)
        // {
        //     var schemasPath = Application.dataPath + "AddressableAssetsData/AssetGroups/Schemas";
        //     Directory.GetFiles(schemasPath, "**.asset", SearchOption.AllDirectories);   
        // }
    }
    
    #region Display Group
    
        [FoldoutGroup("添加"), HideLabel]
        public GroupHandle DisplayAddHandle;

        [Button("添加", ButtonSizes.Large), GUIColor(0.7f, 0.7f, 0.2f), FoldoutGroup("添加")]
        public void AddGroup()
        {
            if (DisplayAddHandle == null)
            {
                DisplayAddHandle = new GroupHandle();
            }

            if (string.IsNullOrEmpty(DisplayAddHandle.GroupName) ||  
                groups.Contains(DisplayAddHandle) || 
                groups.Find(g => g.GroupName == DisplayAddHandle.GroupName) != null)
            {
                EditorUtility.DisplayDialog("警告", "以含有对应 group 名称 或\n 对应 groupName 不能为空", "ok", "哦");
                return;
            }

            groups.Add(DisplayAddHandle);
            
            Debug.Log("[AddressableGroupsManager] 添加成功：" + DisplayAddHandle.GroupName);
        }

        
        [Button("重置", ButtonSizes.Large), GUIColor(0.7f, 0.2f, 0.2f), FoldoutGroup("添加")]
        public void ResetGroup()
        {
            if (DisplayAddHandle == null)
            {
                DisplayAddHandle = new GroupHandle();
            }

            DisplayAddHandle = new GroupHandle();
        }


        #endregion

        
    private void defaultBuild()
    {
        // 开始构建
        for (int i = 0; i < groups.Count; i++)
        {
            groups[i].Build();
        }
    }

    private void publishBuild()
    {
        for (int i = 0; i < groups.Count; i++)
        {
            var group = groups[i];
            if (!group.isDLC)
            {
                group.Build();
            }
        }
    }
    
    // 工程暂时注销
    private void dlcBuild()
    {
        return;
        var aa_setting = AAManagementUtils.GetSettings();
        AddressablesPlayerBuildResult result = null;
        
        for (int i = 0; i < groups.Count; i++)
        {
            var group = groups[i];
            if (group.isDLC)
            {
                group.Build();
                if (!group.SwitchToRemote())
                {
                    Debug.LogError("【AddressableGroupManager】switch remote schema error: " + group.GroupName);
                    return;
                }

                VersionCatalog.DLCName = group.GroupName;
                //AddressableAssetSettings.BuildPlayerContent(out result);
                AAManagementUtils.CustomBuilding(out result);
                
                // error stop
                if (result.Error.Length > 0)
                {
                    Debug.LogError("构建中止");
                    return;
                }

                ClearGroups();

                AddressableAssetSettings.CleanPlayerContent();
                EditorUtility.SetDirty(aa_setting);
                AssetDatabase.Refresh();
                AssetDatabase.SaveAssets();
                
                #if UNITY_2018
                // Addressable 构建 Catalog 名称会有缓存，导致错误，尝试手动修复。 Default Build 无法自定义，Custom Build 就可以尝试修复了
                var profileId = aa_setting.profileSettings.GetProfileId("DLC");
                if (!string.IsNullOrEmpty(profileId))
                {
                    // remoteBuild 
                    var rtbPath = aa_setting.profileSettings.GetValueByName(profileId, "RemoteBuildPath");
                    var relaPath = aa_setting.profileSettings.EvaluateString(profileId, rtbPath);
                    var buildPath = Application.dataPath.Replace("Assets", relaPath);

                    var catalogs = Directory.GetFiles(buildPath, "**.**", SearchOption.AllDirectories)
                        .Where(file => file.EndsWith("hash") || file.EndsWith("json")).ToArray();

                    for (int j = 0; j < catalogs.Length; j++)
                    {
                        var f = catalogs[j];
                        var name = Path.GetFileNameWithoutExtension(f);
                        var nf = f.Replace(name, $"catalog_{group.GroupName}");
                        System.IO.File.Move(f, nf);
                    }
                }
                else
                {
                    Debug.LogError("【AddressableGroupManager】profile get error. " + group.GroupName);
                }
                #endif

                Debug.Log("【AddressableGroupManager】build success. " + group.GroupName);
            }
        }
    }

    // update group 检测
    [Button("更新 Content", ButtonSizes.Large), GUIColor(0.2f, 0.78f, 0.5f), FoldoutGroup("构建")]
    public void UpdateContent()
    {
        Debug.Log("更新构建");
        ContentUpdateScript.GatherModifiedEntriesWithDependencies(AAManagementUtils.GetSettings(), "");
    }

    
    // 删除所有 Groups
    public void ClearGroups()
    {
        var aa_setting = AAManagementUtils.GetSettings();
        if (isClearGroup)
        {
            ClearSetting();
            

            var groups = aa_setting.groups;
            for (int i = 0; i < groups.Count; i++)
            {
                aa_setting.RemoveGroup(groups[i]);
            }
        }
    }

    /// <summary>
    /// 清除 Addressable Setting 基本属性
    /// </summary>
    public void ClearSetting()
    {
        // label 根据 groupHandles 的属性动态添加
        var setting = AAManagementUtils.GetSettings();
        var labels = setting.GetLabels();
        for (int i = 0; i < labels.Count; i++)
        {
            setting.RemoveLabel(labels[i]);
        }
        
        EditorUtility.SetDirty(setting);
        AssetDatabase.Refresh();
        AssetDatabase.SaveAssets();
    }
    
    /// <summary>
    /// 切换工程类型
    /// </summary>
    /// <param name="ptype"></param>
    public void ProjectTypeSwitch(ProjectType ptype)
    {
        switch (ptype)
        {
            case ProjectType.DLC:
                AAManagementUtils.SwitchProfilerRemotePath("DLC");
                AAManagementUtils.GetSettings().ContentStateBuildPath = "[VersionCatalog.DLCName]";
                break;
            case ProjectType.Publish:
                AAManagementUtils.SwitchProfilerRemotePath("Remote");
                AAManagementUtils.GetSettings().ContentStateBuildPath = "";
                break;
            case ProjectType.Development:
                AAManagementUtils.SwitchProfilerRemotePath("Local");
                AAManagementUtils.GetSettings().ContentStateBuildPath = "";
                break;
            default:
                break;
        }
        
        EditorUtility.SetDirty(AAManagementUtils.GetSettings());
        Debug.Log("[AddressableGroupsManager] Switch Project profiler: " + ptype.ToString());
    }
    
}

[Serializable]
public class GroupHandle
{
    /// <summary>
    /// 组名称
    /// </summary>
    [LabelText("名称"), BoxGroup("Basic")] public string GroupName = "";

    [LabelText("组标签Label"), LabelWidth(100), BoxGroup("Basic")]
    public string GroupLabel = "";

    [LabelText("额外名称后缀"), LabelWidth(100), BoxGroup("Basic")]
    public string extraName = "";
    
    [BoxGroup("Basic"), LabelText("不打入主包(DLC)"), ToggleLeft]
    public bool isDLC = false;

    [BoxGroup("Path"), LabelText("仅构建文件夹")]
    public bool PathOnly = false;
    
    /// <summary>
    /// 文件夹路径
    /// </summary>
    [FolderPath, BoxGroup("Path")] public List<string> SubPaths;

    /// <summary>
    /// 文件对象路径
    /// </summary>
    [Sirenix.OdinInspector.FilePath, BoxGroup("Path")] public List<string> ExtraFilePaths;

    [Button("创建", ButtonSizes.Large), GUIColor(0.2f, 0.95f, 0.12f)]
    public void Build()
    {
        if (string.IsNullOrEmpty(GroupName))
        {
            Debug.LogError("【AddressableGroupsManager】 group lost name");
            return;
        }

        var group = AAManagementUtils.GetAAGroup(GroupName);

        if (SubPaths != null)
        { 
            if (!PathOnly) 
            {
                for (int i = 0; i < SubPaths.Count; i++)
                {
                    var folder = SubPaths[i];
                    if (!Directory.Exists(folder))
                    {
                        Debug.LogError("【GroupManagement】 Folder lost: " + folder);
                        continue;
                    }

                    var destPath = $"{Application.dataPath.Replace("Assets", "")}{folder}";
                    var files = Directory.GetFiles(destPath, "**.**",
                        SearchOption.AllDirectories).Where(path => !path.EndsWith("meta")).ToArray();

                    AAManagementUtils.AssignAssets(files, group, GroupLabel, extraName);
                }
            }
            else
            {
                AAManagementUtils.AssignAssets(SubPaths.ToArray(), group, GroupLabel, extraName);
            }
        }

        if (ExtraFilePaths != null)
        {
            AAManagementUtils.AssignAssets(ExtraFilePaths.ToArray(), group, GroupLabel, extraName);
        }


        EditorUtility.SetDirty(group);
    }

    /// <summary>
    /// 切换到远端模式 构建 
    /// </summary>
    /// <returns></returns>
    public bool SwitchToRemote()
    {
        try
        {
            var setting = AAManagementUtils.GetSettings();
            var bundleSchema = AAManagementUtils.GetGroupSchema(GroupName);
            bundleSchema.BuildPath.SetVariableByName(setting, "RemoteBuildPath");
            bundleSchema.LoadPath.SetVariableByName(setting, "RemoteLoadPath");

            return true;
        }
        catch (Exception e)
        {
            Debug.LogError("【AddressableGroupManager】 bundle schema lost in: " + GroupName);
            return false;
        }
    }

}

// DLC project 依赖类
public static class VersionCatalog
{
    /// <summary>
    /// for catalog main 
    /// </summary>
    public static string DLCName = "";
}

#endif